#coding:utf-8
import os.path

filename='student.txt'  # 全局变量，使用范围整个模块中所有的函数
def menu():
    print('''
    ----------------学生信息管理系统------------------
    ===================功能菜单=====================
            1.录入学生信息
            2.查找学生信息
            3.删除学生信息
            4.修改学生信息
            5.排序
            6.统计学生总人数
            7.显示所有学生信息
            0.退出
    ===============================================
    ''')
def main():
    while True:
        menu()  # 调用本模块中的函数
        option=eval(input('请选择:'))
        if option in [i for i in range(8)]:
            if option==0:
                print('您已退出学生管理系统!!!')
                break
            elif option==1:
                insert() # 调用新增的函数
            elif option==2:
                search() # 调用查询的函数
            elif option==3:
                delete() # 调用删除的函数
            elif option==4:
                modify() # 调用修改的函数
            elif option==5:
                sort()
            elif option==6:
                total()
            elif option==7:
                show()
            # 要不要加else，不需要else
        else:
            print('对不起，功能菜单选择有误!!!')

def insert():
    student_lst=[] # 数据的存储结构是列表,列表中存储的元素为字典类型
    # 每一个元素（字典）就是一条学生信息
    while True:
        id=input('请输入ID:(如:1001)')
        if not id : # 利用到了对象的布尔值 if id==''
            break
        name=input('请输入学生姓名:')
        if not name: # if name=='':
            break
        try:
            english=eval(input('请输入英语成绩:'))
            python=eval(input('请输入Python成绩:'))
            c=eval(input('请输入c语言成绩'))
        except:
            print('输入成绩无效，不是数值型，请重新输入!!!')
            continue # 回到while True
        # 所有数据都录入完毕
        student={'id':id,'name':name,'english':english,'python':python,'c':c}
        # 将一条学生信息添加到学生列表中
        student_lst.append(student) #
        # 询问是否继续添加
        answer=input('是否继续添加(y/n)?')
        if answer not in ['y','Y']:
            break # 退出while循环

    # 录入完学生信息，将学生信息进行保存
    # save()叫保存学生信息到文本文件，也叫数据的持久化
    save(student_lst) # 函数的调用，student_lst是函数的实参
def save(lst): # lst是学生列表，元素是字典类型
    try:
        student_txt=open(filename,'a') # 如果追加方式打开文件报错
    except Exception as e:
        student_txt=open(filename,'w') # 覆盖写的方式打开

    for info in lst: # 遍历学生信息列表,info是字典类型
        student_txt.write(str(info)+'\n') # 把整个字典转成了str
    student_txt.close() # 关闭文件

def search():
    student_query=[] # 存储查询到的学生 每个学生信息都是一个字典类型
    while True:
        id=''
        name=''
        if os.path.exists(filename):
            mode=eval(input('按ID查输入1:按姓名查输入2:'))
            if mode==1:
                id=input('请输入要查询的学生学号:')
            elif mode==2:
                name=input('请输入要查询的学生姓名')
            else:
                print('输入有误，请重新输入！！！')
                search() # 自己调用自己
            with open(filename,'r') as file:
                student_lst=file.readlines() # 读取文本文件中的全部数据，结果是列表类型
                for item in student_lst: # 遍历列表，item是字符串类型
                    d=eval(item) # 转成字典类型 ，一个d就是一条学生信息
                    if id!='': # 根据id查询
                        # d['id']与d.get('id')功能相同
                       if d.get('id')==id :# 等值判断 ，字典中的id与要查询的id
                           student_query.append(d) # 如果查到，就将学生信息,放到列表中

                    if name !='':
                        if d.get('name')==name:
                            student_query.append(d)
                show_student(student_query) # 调用了一个函数，显示查询结果
                #本次查询之后，要将列表清空
                student_query.clear()
                answer=input('是否继续查询(y/n)?')
                if answer.upper()!='Y':
                    break # 退出的是while循环



        else:
            print('暂未保存数据信息！！！')
            return  # 结束函数
def show_student(student_query): # student_query函数的形参
    if not student_query: # 利用到了对象的布尔值 空列表的布尔值为False
        print('无查询数据')
        return
    # Python中的格式化字符串有三种方式 f-string 对象的format()  %
    format_title='{:^4}\t{:^8}\t{:^6}\t{:^6}\t{:^6}\t{:^6}'
    print(format_title.format('ID','姓名','英语','Python','C语言','总成绩'))
    format_date='{:^4}\t{:^8}\t{:^6}\t{:^6}\t{:^6}\t{:^6}'
    for info in student_query: # info是学生信息，字典类型
        print(format_date.format(info.get('id'),
                                 info.get('name'),
                                 str(info.get('english')),
                                 str(info.get('python')),
                                 str(info.get('c')),
                                 str(info.get('english')+info.get('python')+info.get('c'))))
# show_student()和show()的区别  show_student()是显示数据 show是从文件读数据
def delete():
    while True:
        student_id=input('请输入要删除的学生的ID:')
        if student_id.strip()!='': # strip()去掉字符串左右的空格
            if os.path.exists(filename):
                with open(filename,'r') as rfile:
                    student_old=rfile.readlines() # student_old是列表类型
            else:
                student_old=[] # 文件在磁盘上不存时，学生信息是一个空列表
            # 是否执行删除操作？
            flag=False  # 标记是否可删除
            if student_old: # 列表不为空的时候
                with open(filename,'w') as wfile: # 为什么必须用覆盖写
                    d={}
                    for item in student_old:
                        d=eval(item) # 类型转换，将字符串转成字典类型
                        # 判断是否是要删除的学生？
                        if d.get('id')!=student_id: # 与要删除的学员不是同一个
                            wfile.write(str(d)+'\n')
                        else:
                            flag=True # 修改标记为可删除
                    if flag:
                        print(f'ID为{student_id}的学生信息已被删除')
                    else:
                        print(f'没有找到ID为{student_id}的学生信息')
            else:
                print('无学生信息')
                break # 退出循环
            # 显示所有学生信息
            show() # 调用本模块中的show()函数
            answer=input('是否继续删除(y/n)?')
            if answer not in ['Y','y']:
                break # 退出循环

        # 如果student_id是一个空字符串，会重新循环
def modify():
    # 修改的第1步，从文件中读取数据
    if os.path.exists(filename):
        with open(filename,'r') as file:
            student_old=file.readlines() # student_old是列表类型
    else:
        return
    student_id=input('请输入要修改的学生的学号:')
    # 修改就是以覆盖写的方式重新把数据写入到文本文件中
    with open(filename,'w') as wfile:
        for stu in student_old: # stu是字符串类型
            d=eval(stu)  # 将字符串类型转成字典类型
            # 什么样的学生是原封不动写入文件？什么样的是要修改之后再写入文件
            if d.get('id')==student_id: # 该学生需要被修改
                while True: # 为什么用while True:
                    try: # d['name']可不可以修改为d.get('name')
                        d['name']=input('请输入学生姓名:')
                        d['english']=eval(input('请输入英语成绩:'))
                        d['python']=eval(input('请输入python的成绩:'))
                        d['c']=eval(input('请输入C语言的成绩:'))
                    except :
                        print('您的修改输入有误，请重新输入')
                    else: # 无异常时就会执行else中的代码 try-else
                        break # 退出的是while True
                wfile.write(str(d)+'\n') # 修改后写入
            else:
                wfile.write(str(d)+'\n') # 原封不动写入

    answer=input('是否继续修改其他同学?(y/n):')
    if answer.upper()=='Y':
        modify()
def show():
    student_lst=[]
    if os.path.exists(filename):
        with open(filename,'r') as file:
            student_old=file.readlines() # 从文件中读取全部数据
        for item in student_old: # 遍历列表，student_old的内容是字符串类型jf
            student_lst.append(eval(item)) # 将字符串转字典，再添加到列表中
        #调用show_student即可
        show_student(student_lst)
    else:
        print('暂未保存数据！！！')  # show(0
def total():
    if os.path.exists(filename):
        with open(filename,'r') as file:
            student_old=file.readlines() # 列表类型
            if student_old: # 有student.txt文件，但是文件是空白
                print(f'一共有:{len(student_old)}名学生')
            else:
                print('还没有录入学生信息！')
    else:
        print('暂未保存学生信息')
def sort():
    show()
    # 排序之前需要将数据从文件中读取
    if os.path.exists(filename):
        with open(filename,'r') as file:
            student_old=file.readlines() # 列表类型,列表中的元素是字符串
            student_new=[]
            for item in student_old: #item是字符串类型
                d=eval(item) # 将字符串转成字典类型
                student_new.append(d)     # student_new列表中的元素去排序
    else:
        return   # 直接结束函数
    asc_or_desc=input('请选择(0:升序,1:降序)')
    if asc_or_desc=='0':
        asc_or_desc_bool=False # 表示升序
    elif asc_or_desc=='1':
        asc_or_desc_bool=True # 表示降序
    else:
        print('您输入的有误，请重新输入')
        return

    mode=input('请输入排序的方式:1.按英语成绩排序 2.按Python成绩排序 3.按C语言成绩排序 0.按总成绩去排序')
    if mode=='1': # x是lambda的参数，列表中元素 ，是字典类型x.get()字典取值
        student_new.sort(key=lambda x:x.get('english'),reverse=asc_or_desc_bool)
    elif mode=='2':
        student_new.sort(key=lambda x: x.get('python'), reverse=asc_or_desc_bool)
    elif mode=='3':
        student_new.sort(key=lambda x: x.get('c'), reverse=asc_or_desc_bool)
    elif mode=='0':
        student_new.sort(key=lambda x: (x.get('english')+x.get('python')+x.get('c')),
                         reverse=asc_or_desc_bool)
    else:
        print('排序方式选择有误，请重新输入')
        return
    show_student(student_new) # 函数的调用
if __name__ == '__main__':
    main() # insert(),delete(),modify()total()show()sort()都是在main中调用

# 18602218136  atxunda.com
# 第三方库 PyInstaller  需要安装才能使用 pip install pyinstaller
# 打包的语法结构  pyinstaller -F Python文件的完整路径